import streamlit as st
import pandas as pd
import numpy as np
import plotly.express as px
import os
import json
from pathlib import Path
from audio_transcriber import AudioExtractorTranscriber
from content_analyzer import ContentAnalyzer
from speech_analyzer import SpeechAnalyzer, ResultsGenerator
from video_frame_extractor import VideoFrameExtractor
from frame_analyzer import SimpleImageAnalyzer, ResultsGenerator as FrameResultsGenerator
from score_generator import Scorer
from bias_detector import BiasDetector
import time

# Configuration
SCORES_DIR = "scores"
VIDEOS_DIR = "videos"
TEMP_DIR = "temp"

st.set_page_config(page_title="候选人视频分析", layout="wide")

def load_candidate_scores(scores_dir=SCORES_DIR):
    scores_data = {}
    for candidate_dir in Path(scores_dir).glob("*"):
        if candidate_dir.is_dir():
            json_file = candidate_dir / "report.json"
            if json_file.exists():
                with open(json_file, 'r', encoding='utf-8') as f:
                    scores_data[candidate_dir.name] = json.load(f)
    return scores_data

def process_video(video_file, candidate_name, position, job_keywords, demographics_data=None):
    os.makedirs(TEMP_DIR, exist_ok=True)
    temp_video_path = os.path.join(TEMP_DIR, f"{candidate_name}_{video_file.name}")
    with open(temp_video_path, 'wb') as f:
        f.write(video_file.read())
    
    video_id = f"{candidate_name}_{video_file.name.split('.')[0]}"  # 定义 video_id
    
    try:
        # 第1步：提取帧
        st.write("第1步：提取视频帧...")
        frame_extractor = VideoFrameExtractor()
        frame_result = frame_extractor.process_folder(TEMP_DIR, "frames")
        frame_folder = frame_result[next(iter(frame_result))]["frames_folder"]
        st.write(f"帧提取结果：{frame_result}")
        
        # 第2步：转录音频
        st.write("第2步：转录音频...")
        audio_transcriber = AudioExtractorTranscriber()
        audio_result = audio_transcriber.process_folder(TEMP_DIR, "transcripts")
        
        # 第3步：分析语音
        st.write("第3步：分析语音...")
        speech_analyzer = SpeechAnalyzer()
        speech_result = speech_analyzer.analyze_speech(temp_video_path)
        if speech_result:
            generator = ResultsGenerator(speech_result, video_id)  # 传递video_id
            generator.save_results()
        
        # 第4步：分析内容
        st.write("第4步：分析内容...")
        content_analyzer = ContentAnalyzer()
        content_result = content_analyzer.process_folder("transcripts", "analysis_results", job_keywords.split(","))
        
        # 第5步：分析视觉帧
        st.write("第5步：分析视觉帧...")
        frame_analyzer = SimpleImageAnalyzer()
        frame_analysis_result = frame_analyzer.analyze_image_folder(frame_folder)
        if frame_analysis_result:
            frame_generator = FrameResultsGenerator(frame_analysis_result)
            frame_generator.save_results(video_id=video_id)  # 传递 video_id
        else:
            st.error("视觉帧分析失败，未生成结果。")
        
        # 第6步：生成评分
        st.write("第6步：生成评分...")
        scorer = Scorer()
        score_result = scorer.process(video_id)
        
        if score_result:
            st.subheader("评分详情")
            visual_features = score_result['features']['visual']
            st.write("### 视觉得分")
            st.write(f"- 眼神接触：{visual_features['eye_contact']:.2f}")
            st.write(f"- 姿势：{visual_features['posture']:.2f}")
            st.write(f"- 表情多样性：{visual_features['expression_variation']:.2f}")
            st.write(f"**总分：{score_result['component_scores']['visual']:.1f}**")
            
            audio_features = score_result['features']['audio']
            st.write("### 音频得分")
            st.write(f"- 语速：{audio_features['speaking_rate']:.2f}（每分钟）")
            st.write(f"- 音调变化：{audio_features['pitch_variation']:.2f}")
            st.write(f"- 音量变化：{audio_features['volume_variation']:.2f}")
            st.write(f"- 清晰度：{audio_features['clarity']:.2f}")
            st.write(f"**总分：{score_result['component_scores']['audio']:.1f}**")
            
            content_features = score_result['features']['content']
            st.write("### 内容得分")
            st.write(f"- 关键词相关性：{content_features['keyword_relevance']:.2f}")
            st.write(f"- 自信度：{content_features['confidence']:.2f}")
            st.write(f"- 清晰度：{content_features['clarity']:.2f}")
            st.write(f"**总分：{score_result['component_scores']['content']:.1f}**")
            
            st.write("### 综合得分")
            st.write(f"**总分：{score_result['overall_score']:.1f}**")
            
            # 第7步：偏见检测（如果有人口统计学数据）
            if demographics_data:
                st.write("第7步：偏见检测分析...")
                try:
                    bias_detector = BiasDetector()
                    # 创建评分数据列表和人口统计学数据字典
                    scores_list = [score_result]
                    demographics_dict = {video_id: demographics_data}
                    
                    # 执行偏见检测
                    bias_results = bias_detector.check_bias(scores_list, demographics_dict)
                    
                    # 保存偏见分析报告
                    bias_output_dir = f"bias_analysis_results/{video_id}"
                    os.makedirs(bias_output_dir, exist_ok=True)
                    report_paths = bias_detector.save_bias_report(bias_results, bias_output_dir)
                    
                    # 显示偏见分析结果
                    st.write("### 偏见检测结果")
                    if bias_results and 'metrics' in bias_results:
                        for metric_name, metric_value in bias_results['metrics'].items():
                            if isinstance(metric_value, dict):
                                st.write(f"#### {metric_name}")
                                for sub_metric, value in metric_value.items():
                                    if isinstance(value, (int, float)):
                                        st.write(f"- {sub_metric}: {value:.3f}")
                                    else:
                                        st.write(f"- {sub_metric}: {value}")
                            else:
                                if isinstance(metric_value, (int, float)):
                                    st.write(f"- {metric_name}: {metric_value:.3f}")
                                else:
                                    st.write(f"- {metric_name}: {metric_value}")
                        
                        # 显示偏见评估结论
                        if 'conclusion' in bias_results:
                            st.write("#### 偏见评估结论")
                            st.write(bias_results['conclusion'])
                            
                            if 'recommendations' in bias_results:
                                st.write("#### 推荐措施")
                                for rec in bias_results['recommendations']:
                                    st.write(f"- {rec}")
                except Exception as e:
                    st.error(f"偏见检测分析失败: {str(e)}")
        else:
            st.error("评分生成失败，请检查日志。")
        
        return score_result
    
    except Exception as e:
        st.error(f"处理视频出错：{str(e)}")
        return None
    finally:
        if os.path.exists(temp_video_path):
            os.remove(temp_video_path)

def show_upload_page():
    st.header("上传候选人视频")
    
    uploaded_file = st.file_uploader("选择视频文件", type=["mp4", "mov", "avi"])
    
    if uploaded_file is not None:
        st.video(uploaded_file)
        
        # 收集人口统计学数据（在表单外）
        st.write("### 可选：输入人口统计学数据用于偏见检测")
        st.write("注意：如果不需要偏见检测分析，可以跳过此步骤")
        
        # 默认为无人口统计学数据
        demographics_data = None
        
        # 允许用户选择是否添加人口统计学数据
        collect_demographics = st.checkbox("添加人口统计学数据", value=False)
        
        if collect_demographics:
            col1, col2 = st.columns(2)
            with col1:
                gender = st.selectbox("性别", ["未指定", "男", "女", "其他"])
                age_group = st.selectbox("年龄段", ["未指定", "18-25", "26-35", "36-45", "46-55", "56+"])
            with col2:
                education = st.selectbox("教育程度", ["未指定", "高中", "本科", "硕士", "博士"])
                ethnicity = st.selectbox("民族", ["未指定", "汉族", "其他少数民族"])
            
            if gender != "未指定" or age_group != "未指定" or education != "未指定" or ethnicity != "未指定":
                demographics_data = {
                    "gender": gender if gender != "未指定" else None,
                    "age_group": age_group if age_group != "未指定" else None,
                    "education": education if education != "未指定" else None,
                    "ethnicity": ethnicity if ethnicity != "未指定" else None
                }
        
        with st.form("候选人信息"):
            candidate_name = st.text_input("候选人姓名", "")
            position = st.text_input("应聘职位", "")
            job_keywords = st.text_input("职位关键词（逗号分隔）", "")
            
            submitted = st.form_submit_button("处理视频")
            if submitted:
                if not candidate_name or not position or not job_keywords:
                    st.error("请填写所有字段：候选人姓名、应聘职位和职位关键词！")
                else:
                    with st.spinner("正在处理视频... 这可能需要几分钟"):
                        # 修改process_video调用，传入demographics_data参数
                        result = process_video(uploaded_file, candidate_name, position, job_keywords, demographics_data)
                        if result:
                            st.success(f"{candidate_name} 的视频处理成功！")
                        else:
                            st.error("视频处理失败，请检查输入或日志。")

def show_analysis_page():
    st.header("候选人分析结果")
    
    scores_data = load_candidate_scores()
    if not scores_data:
        st.write("暂无分析结果，请先上传视频进行分析。")
        return
    
    # 添加视图选择
    view_mode = st.radio("选择视图", ["单个候选人详细分析", "多候选人比较"])
    
    if view_mode == "单个候选人详细分析":
        # 显示候选人列表
        st.subheader("选择候选人")
        candidate_names = list(scores_data.keys())
        selected_candidate = st.selectbox("候选人", candidate_names)
        
        if selected_candidate:
            candidate_data = scores_data[selected_candidate]
            
            st.subheader(f"{selected_candidate} 的分析结果")
            
            # 显示总体评分
            st.metric("总体评分", f"{candidate_data['overall_score']:.1f}/10")
            
            # 创建评分数据表格
            component_scores = candidate_data['component_scores']
            component_df = pd.DataFrame({
                "评分项": ["视觉表现", "语音表现", "内容相关性"],
                "得分": [component_scores['visual'], component_scores['audio'], component_scores['content']]
            })
            
            # 绘制柱状图
            fig = px.bar(component_df, x="评分项", y="得分", color="评分项", 
                        color_discrete_sequence=["#1f77b4", "#ff7f0e", "#2ca02c"],
                        range_y=[0, 100], title="评分明细")
            st.plotly_chart(fig)
            
            # 显示详细特征
            features = candidate_data['features']
            
            col1, col2, col3 = st.columns(3)
            
            with col1:
                st.write("### 视觉表现")
                visual_df = pd.DataFrame({
                    "特征": ["眼神接触", "姿势", "表情多样性"],
                    "得分": [features['visual']['eye_contact'], 
                            features['visual']['posture'], 
                            features['visual']['expression_variation']]
                })
                st.dataframe(visual_df)
            
            with col2:
                st.write("### 语音表现")
                audio_df = pd.DataFrame({
                    "特征": ["语速", "音调变化", "音量变化", "清晰度"],
                    "得分": [features['audio']['speaking_rate'], 
                            features['audio']['pitch_variation'], 
                            features['audio']['volume_variation'],
                            features['audio']['clarity']]
                })
                st.dataframe(audio_df)
            
            with col3:
                st.write("### 内容表现")
                content_df = pd.DataFrame({
                    "特征": ["关键词相关性", "自信度", "清晰度"],
                    "得分": [features['content']['keyword_relevance'], 
                            features['content']['confidence'], 
                            features['content']['clarity']]
                })
                st.dataframe(content_df)
            
            # 显示雷达图
            st.subheader("能力雷达图")
            
            # 准备雷达图数据
            radar_data = {
                "能力": ["眼神接触", "姿势", "表情多样性", "语速", "音调变化", "音量变化", 
                        "语音清晰度", "关键词相关性", "自信度", "内容清晰度"],
                "得分": [
                    features['visual']['eye_contact'], 
                    features['visual']['posture'], 
                    features['visual']['expression_variation'],
                    features['audio']['speaking_rate'], 
                    features['audio']['pitch_variation'], 
                    features['audio']['volume_variation'],
                    features['audio']['clarity'],
                    features['content']['keyword_relevance'], 
                    features['content']['confidence'], 
                    features['content']['clarity']
                ]
            }
            
            radar_df = pd.DataFrame(radar_data)
            fig = px.line_polar(radar_df, r="得分", theta="能力", line_close=True)
            fig.update_layout(
                polar=dict(
                    radialaxis=dict(
                        visible=True,
                        range=[0, 1]
                    )
                ),
                showlegend=False
            )
            st.plotly_chart(fig)
    else:
        # 多候选人比较视图
        st.subheader("候选人比较")
        
        # 选择要比较的候选人
        candidate_names = list(scores_data.keys())
        if len(candidate_names) < 2:
            st.warning("至少需要两名候选人才能进行比较。请先上传更多候选人视频。")
            return
            
        selected_candidates = st.multiselect("选择要比较的候选人", candidate_names, default=candidate_names[:min(3, len(candidate_names))])
        
        if len(selected_candidates) < 2:
            st.warning("请至少选择两名候选人进行比较。")
            return
            
        # 准备总体评分比较
        overall_scores = []
        component_data = []
        
        for candidate in selected_candidates:
            candidate_data = scores_data[candidate]
            
            # 总体评分
            overall_scores.append({
                "候选人": candidate,
                "总分": candidate_data['overall_score']
            })
            
            # 组件评分
            component_scores = candidate_data['component_scores']
            component_data.append({
                "候选人": candidate,
                "视觉表现": component_scores['visual'],
                "语音表现": component_scores['audio'],
                "内容相关性": component_scores['content']
            })
        
        # 转换为DataFrame
        overall_df = pd.DataFrame(overall_scores)
        component_df = pd.DataFrame(component_data)
        
        # 绘制总体评分对比图
        st.subheader("总体评分对比")
        fig1 = px.bar(overall_df, x="候选人", y="总分", color="候选人", range_y=[0, 100])
        st.plotly_chart(fig1)
        
        # 绘制各组件评分对比图
        st.subheader("各维度评分对比")
        component_melted = pd.melt(component_df, id_vars=["候选人"], var_name="评分项", value_name="得分")
        fig2 = px.bar(component_melted, x="候选人", y="得分", color="评分项", barmode="group", range_y=[0, 100])
        st.plotly_chart(fig2)
        
        # 绘制雷达图对比
        st.subheader("能力雷达图对比")
        
        # 准备雷达图数据
        radar_dfs = []
        for candidate in selected_candidates:
            candidate_data = scores_data[candidate]
            features = candidate_data['features']
            
            radar_data = {
                "能力": ["眼神接触", "姿势", "表情多样性", "语速", "音调变化", "音量变化", 
                        "语音清晰度", "关键词相关性", "自信度", "内容清晰度"],
                "得分": [
                    features['visual']['eye_contact'], 
                    features['visual']['posture'], 
                    features['visual']['expression_variation'],
                    features['audio']['speaking_rate'], 
                    features['audio']['pitch_variation'], 
                    features['audio']['volume_variation'],
                    features['audio']['clarity'],
                    features['content']['keyword_relevance'], 
                    features['content']['confidence'], 
                    features['content']['clarity']
                ],
                "候选人": [candidate] * 10
            }
            radar_dfs.append(pd.DataFrame(radar_data))
        
        # 合并所有雷达图数据
        combined_radar_df = pd.concat(radar_dfs)
        
        # 绘制多候选人雷达图
        fig3 = px.line_polar(combined_radar_df, r="得分", theta="能力", color="候选人", line_close=True)
        fig3.update_layout(
            polar=dict(
                radialaxis=dict(
                    visible=True,
                    range=[0, 1]
                )
            )
        )
        st.plotly_chart(fig3)

def main():
    # 设置边栏
    st.sidebar.title("视频面试分析系统")
    
    # 页面选择
    page = st.sidebar.radio("选择页面", ["上传视频", "查看分析结果"])
    
    if page == "上传视频":
        show_upload_page()
    else:
        show_analysis_page()

if __name__ == "__main__":
    main()